/**
 *
 */
package com.jcode.netty.server;

import com.jcode.netty.cmd.SysRequestCode;
import com.jcode.netty.protocol.Packet;
import com.jcode.netty.protocol.PacketUtil;
import com.jcode.netty.util.RemotingUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 连接管理
 * <p>
 * TODO 连接控制、集群可以存储到缓存中 clientId-serverNode
 *
 * @Author dreajay
 * @DateTime 2016年11月14日 下午2:43:49
 */
public class ConnectionManager {

    private DefaultChannelGroup channelGroup = new DefaultChannelGroup("defaultChannelGroup", GlobalEventExecutor.INSTANCE);

    private ConcurrentHashMap<String, ClientInfo> clientMap = new ConcurrentHashMap<String, ClientInfo>();

    private static final Logger logger = LoggerFactory.getLogger(ConnectionManager.class);

    private ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<String, Session>();

    private AtomicLong connectionCount = new AtomicLong(0);

    private NettyServer server;

    private AtomicBoolean send = new AtomicBoolean(false);


    public ConnectionManager(final NettyServer server) {
        this.server = server;
    }

    /**
     * 添加连接
     *
     * @param channel
     * @return
     */
    public boolean addConnect(Channel channel) {
        // TODO 连接控制：1.连接数限制，2.相同地址客户端只连接一个，3.多终端连接问题
//        if (channelGroup.size() >= maxConnectSize) {
//            logger.error("服务器连接数超过上限：" + maxConnectSize);
//            return false;
//        }

        boolean result = channelGroup.add(channel);
        logger.info("添加客户端连接：{}，当前连接数：{}", channel, channelGroup.size());
        if(result) {
            if (connectionCount.get() >= server.getConfig().getMaxConnectionSize()) {
                if(send.compareAndSet(false, true)) {
                    sendMsg();
                }
            }
        }
        return result;
    }

    /**
     * 关闭连接
     *
     * @param channel
     * @return
     */
    public boolean closeConnect(Channel channel) {
        boolean result = channelGroup.remove(channel);
        if (result) {
            RemotingUtil.closeChannel(channel);
            logger.info("关闭客户端连接：{}，当前连接数：{}", channel, channelGroup.size());
        }
        return result;
    }

    /**
     * 当前连接数
     *
     * @return
     */
    public long getConnectionSize() {
        return channelGroup.size();
    }

    public Channel getConnection(ChannelId id) {
        return channelGroup.find(id);
    }

    /**
     * 获取连接所在节点
     *
     * @param id
     * @return
     */
    public ServerNode getServerNode(ChannelId id) {
        return null;
    }


    private void sendMsg() {
        logger.info("channel size：{}", channelGroup.size());
        long begin = System.currentTimeMillis();
        Iterator<Channel> it = channelGroup.iterator();
        while (it.hasNext()) {
            try {
                Channel channel = it.next();
                Packet packet = PacketUtil.createRequestPacket(SysRequestCode.PING);
                packet.addExtField("serverAddress", channel.localAddress().toString());
                packet.addExtField("clientAddress", channel.remoteAddress().toString());
                server.sendRequestOneway(channel, packet, 60000);
                logger.info("=======sequenceId:{}", packet.getSequenceId());
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        long end = System.currentTimeMillis();
        logger.error("发送用户数：{}，耗时{}ms", getConnectionSize(), (end - begin));
    }

}
